package geldautomat;

import bank_access.KontoException;
import bank_access.KontoImplBase;
import bank_access.ManagerImplBase;
import geldautomat.connect.ConnectDialog;
import java.awt.Button;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Frame;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.Label;
import java.awt.Panel;
import java.awt.TextField;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import mware_access.MiddlewareService;
import mware_access.NameService;

/**
 * GUI-basierte Hauptanwendung des Geldautomaten.
 * 
 */
public class Geldautomat extends Frame implements ActionListener {

    private static final long serialVersionUID = 6751599359033886260L;
    // Textfelder
    private TextField BankTextField, KontoTextField, KontostandTextField, BlzTextField, BetragsTextField, EmpfKontoTextField;
    // Knoepfe
    private Button NeuesKontoButton, EinzahlenButton, AbhebenButton, KStandAktualisierenButton, UeberweisenButton, SerienEinzahlenButton;
    // Statuszeile
    private StatusLine StatusLabel;
    private static String DoneMessage = "Done.";
    private int AnzSerienEinzahlung;
    private final ConnectDialog connectDialog = new geldautomat.connect.ConnectDialog(this, true);
    private MiddlewareService mware;
    private NameService nameservice;
    private ManagerImplBase bank;

    /**
     * Statuszeile des Fensters
     */
    private class StatusLine extends Label {

        private static final long serialVersionUID = -1575611930399336962L;

        public StatusLine(String text) {
            super(text);
            connectDialog.setVisible(true);
            mware = MiddlewareService.init(connectDialog.getHost(), connectDialog.getPort());
            nameservice = mware.getNameService();
            center(this);
        }

        private void center(Component c) {
            Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
            int w = c.getSize().width;
            int h = c.getSize().height;
            c.setLocation((dim.width - w) / 2, (dim.height - h) / 2);
        }

        /**
         * Für normalen Text.
         *
         * @param message
         */
        public void setInfoText(String message) {
            setForeground(Color.BLUE);
            setText(message);
        }

        /**
         * Für Fehlertext.
         *
         * @param message
         */
        public void setErrorText(String message) {
            setForeground(Color.RED);
            setText(message);
        }
    }

    /**
     * Konstruktor.
     * Aufbau der GUI.
     *
     */
    public Geldautomat() {
        super("Geldautomat");

        AnzSerienEinzahlung = 1000;

        //--- Layout manager
        GridBagConstraints constraints = new GridBagConstraints();
        GridBagLayout gridbag = new GridBagLayout();
        setLayout(gridbag);

        //--- Bank (Namenseingabe)
        Label BankLabel = new Label("Bank:        ");
        constraints.insets = new Insets(10, 20, 5, 20);
        constraints.gridwidth = GridBagConstraints.RELATIVE;
        constraints.anchor = GridBagConstraints.WEST;
        gridbag.setConstraints(BankLabel, constraints);
        add(BankLabel);

        BankTextField = new TextField(20);
        constraints.gridwidth = GridBagConstraints.REMAINDER;
        gridbag.setConstraints(BankTextField, constraints);
        add(BankTextField);

        //--- Operation: Konto einrichten
        NeuesKontoButton = new Button("Neues Konto beantragen");
        constraints.anchor = GridBagConstraints.EAST;
        constraints.gridwidth = GridBagConstraints.REMAINDER;
        gridbag.setConstraints(NeuesKontoButton, constraints);
        add(NeuesKontoButton);
        NeuesKontoButton.addActionListener(this);

        //--- Kontoeingabefeld
        Label KontoLabel = new Label("Konto:       ");
        constraints.insets = new Insets(5, 20, 5, 20);
        constraints.anchor = GridBagConstraints.WEST;
        constraints.gridwidth = GridBagConstraints.RELATIVE;
        gridbag.setConstraints(KontoLabel, constraints);
        add(KontoLabel);

        KontoTextField = new TextField(20);
        constraints.gridwidth = GridBagConstraints.REMAINDER;
        gridbag.setConstraints(KontoTextField, constraints);
        add(KontoTextField);

        //--- (Trenner) ------------------------
        Label separatorLabel1 = new Label("----------------------------------------------");
        constraints.insets = new Insets(5, 20, 5, 20);
        gridbag.setConstraints(separatorLabel1, constraints);
        add(separatorLabel1);

        //--- Kontostandfeld
        Label KontostandLabel = new Label("Kontostand:");
        constraints.insets = new Insets(5, 20, 5, 20);
        constraints.gridwidth = GridBagConstraints.RELATIVE;
        gridbag.setConstraints(KontostandLabel, constraints);
        add(KontostandLabel);

        KontostandTextField = new TextField(20);
        KontostandTextField.setEditable(false);
        constraints.gridwidth = GridBagConstraints.REMAINDER;
        gridbag.setConstraints(KontostandTextField, constraints);
        add(KontostandTextField);

        //--- Operation: Kontostand aktualisieren
        KStandAktualisierenButton = new Button("aktualisieren");
        constraints.gridwidth = GridBagConstraints.REMAINDER;
        constraints.anchor = GridBagConstraints.EAST;
        gridbag.setConstraints(KStandAktualisierenButton, constraints);
        add(KStandAktualisierenButton);
        KStandAktualisierenButton.addActionListener(this);

        //--- (Trenner) ------------------------
        Label separatorLabel2 = new Label("----------------------------------------------");
        constraints.insets = new Insets(5, 20, 5, 20);
        constraints.anchor = GridBagConstraints.WEST;
        gridbag.setConstraints(separatorLabel2, constraints);
        add(separatorLabel2);

        //--- Betragsfeld
        Label BetragsLabel = new Label("Betrag:       ");
        constraints.insets = new Insets(10, 20, 5, 20);
        constraints.gridwidth = GridBagConstraints.RELATIVE;
        gridbag.setConstraints(BetragsLabel, constraints);
        add(BetragsLabel);

        BetragsTextField = new TextField(20);
        constraints.gridwidth = GridBagConstraints.REMAINDER;
        gridbag.setConstraints(BetragsTextField, constraints);
        add(BetragsTextField);

        //--- Operation: Einzahlen
        EinzahlenButton = new Button("Einzahlen");
        EinzahlenButton.addActionListener(this);

        //--- Operation: Abheben
        AbhebenButton = new Button("Abheben");
        AbhebenButton.addActionListener(this);

        //--- Operation: Serieneinzahlung
        SerienEinzahlenButton = new Button(AnzSerienEinzahlung + " x Einzahlen");
        SerienEinzahlenButton.addActionListener(this);

        //--- Panel Einzahlen/Abheben
        Panel OpPanel1 = new Panel();
        OpPanel1.setLayout(new FlowLayout());
        OpPanel1.add(EinzahlenButton);
        OpPanel1.add(SerienEinzahlenButton);
        OpPanel1.add(AbhebenButton);
        constraints.gridwidth = GridBagConstraints.REMAINDER;
        constraints.anchor = GridBagConstraints.EAST;
        gridbag.setConstraints(OpPanel1, constraints);
        add(OpPanel1);


        //--- Operation: Ueberweisen (naechste Aufgabe)
        Label EmpfKontoLabel = new Label("  Empfängerkonto:");
        constraints.gridwidth = GridBagConstraints.RELATIVE;
        gridbag.setConstraints(EmpfKontoLabel, constraints);
        add(EmpfKontoLabel);

        EmpfKontoTextField = new TextField(20);
        constraints.gridwidth = GridBagConstraints.REMAINDER;
        gridbag.setConstraints(EmpfKontoTextField, constraints);
        add(EmpfKontoTextField);

        Label BlzLabel = new Label("  BLZ:");
        constraints.gridwidth = GridBagConstraints.RELATIVE;
        gridbag.setConstraints(BlzLabel, constraints);
        add(BlzLabel);

        BlzTextField = new TextField(20);
        constraints.gridwidth = GridBagConstraints.REMAINDER;
        gridbag.setConstraints(BlzTextField, constraints);
        add(BlzTextField);

        UeberweisenButton = new Button("Überweisen");
        constraints.gridwidth = GridBagConstraints.REMAINDER;
        gridbag.setConstraints(UeberweisenButton, constraints);
        add(UeberweisenButton);
        UeberweisenButton.addActionListener(this);


        //--- Statusfeld
        StatusLabel = new StatusLine("                                                                      ");
        constraints.insets = new Insets(20, 20, 20, 20);
        gridbag.setConstraints(StatusLabel, constraints);
        add(StatusLabel);


        /************ Schliessknopf *************/
        addWindowListener(new WindowAdapter() {

            @Override
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        });

        pack();
    }

    /**
     * Hier werden die eigentlichen Aktionen veranlasst.
     */
    public void actionPerformed(ActionEvent e) {
        StatusLabel.setInfoText("");

        if (e.getSource() == KStandAktualisierenButton) {
            //- Pruefung des Kontofeldinhalts
            String kontoID = KontoTextField.getText();
            if (kontoID == null || kontoID.equals("")) {
                StatusLabel.setErrorText("Kontofeld leer bzw. null");
            } else {

                //Kontostand abfragen.
                KontoImplBase konto = (KontoImplBase) nameservice.lookup(kontoID);

                // Kontostandanzeige in GUI aktualisieren:
                KontostandTextField.setText(String.valueOf(konto.kontoStand()));

                StatusLabel.setInfoText(DoneMessage);
            }
        } else if (e.getSource() == NeuesKontoButton) {
            if (BankTextField.getText().trim().length() == 0) {
                StatusLabel.setErrorText("Keine Bank angegeben!");
            } else {
                String kontoIDneu = null;

                /*--------------------------------------
                 * Neues Konto einrichten lassen
                 *  - Checke, ob die Bank da ist
                 *  - Wenn ja, richte ein neues Konto ein
                 * -------------------------------------
                 */
                bank = (ManagerImplBase) nameservice.lookup(BankTextField.getText());
                if (bank == null) {
                    StatusLabel.setErrorText("Nicht verbunden.");
                    return;
                }

                kontoIDneu = bank.kontoEinrichten();


                StatusLabel.setInfoText("Neues konto mit ID " + kontoIDneu + " eingerichtet");
                KontoTextField.setText(kontoIDneu); // ins Kontofeld eintragen
            }
        } else if (e.getSource() == EinzahlenButton) {
            try {
                // Einzuzahlender Betrag
                double betrag = Double.parseDouble(BetragsTextField.getText());

                //- Pruefung des Kontofeldinhalts
                String kontoID = KontoTextField.getText();
                if (kontoID == null || kontoID.equals("")) {
                    StatusLabel.setErrorText("Kontofeld leer bzw. null");
                } else {

                    KontoImplBase konto = (KontoImplBase) nameservice.lookup(kontoID);
                    if (konto == null) {
                        StatusLabel.setErrorText("Konto exisitiert nicht!");
                        return;
                    }
                    try {
                        // Einzahlen veranlassen                         
                        konto.einzahlen(betrag);
                    } catch (KontoException ex) {
                        StatusLabel.setErrorText("Einzahlen nicht möglich: " + ex);
                        return;
                    }

                    // Kontostandanzeige aktualisieren:
                    KontostandTextField.setText(String.valueOf(konto.kontoStand()));

                    StatusLabel.setInfoText(DoneMessage);
                }
            } catch (NumberFormatException e1) {
                StatusLabel.setErrorText("Ungueltiger Betrag!");
            }
        } else if (e.getSource() == AbhebenButton) {
            try {
                // Abzuhebender Betrag
                double betrag = Double.parseDouble(BetragsTextField.getText());

                //- Pruefung des Kontofeldinhalts
                String kontoID = KontoTextField.getText();
                if (kontoID == null || kontoID.equals("")) {
                    StatusLabel.setErrorText("Kontofeld leer bzw. null");
                } else {


                    KontoImplBase konto = (KontoImplBase) nameservice.lookup(kontoID);
                    try {
                        //Abheben veranlassen
                        konto.abheben(betrag);
                    } catch (KontoException ex) {
                        StatusLabel.setErrorText("Abbheben nicht moeglich: " + ex);
                        return;
                    }

                    // Kontostandanzeige aktualisieren:
                    KontostandTextField.setText(String.valueOf(konto.kontoStand()));



                    // Kontostandanzeige aktualisieren:
                    //KontostandTextField.setText(...);

                    StatusLabel.setInfoText(DoneMessage);
                }
            } catch (NumberFormatException e1) {
                StatusLabel.setErrorText("Ungültiger Betrag!");
            }

        } else if (e.getSource() == UeberweisenButton) {
            try {
                // Zu ueberweisender Betrag
                double betrag = Double.parseDouble(BetragsTextField.getText());

                // Bankleitzahl
                String BLZ = BlzTextField.getText();

                //- Pruefung des Kontofeldinhalts
                String kontoID = KontoTextField.getText();
                if (kontoID == null || kontoID.equals("")) {
                    StatusLabel.setErrorText("Kontofeld leer bzw. null");
                } else {
                    //- Pruefung des Empfaengerkontofeldes
                    String eKontoID = EmpfKontoTextField.getText();
                    if (eKontoID == null || eKontoID.equals("")) {
                        StatusLabel.setErrorText("Empfaengerkontofeld leer bzw. null");
                    } else if (BLZ.equals("")) {
                        StatusLabel.setErrorText("Keine Bankleitzahl angegeben!");
                    } else {

                        KontoImplBase konto = (KontoImplBase) nameservice.lookup(kontoID);
                        if (konto == null) {
                            StatusLabel.setErrorText("Konto exisitiert nicht!");
                            return;
                        }
                        try {
                            // Einzahlen veranlassen
                            konto.ueberweise(betrag, BLZ, eKontoID);
                        } catch (KontoException ex) {
                            StatusLabel.setErrorText("Ueberweisen nicht moeglich: " + ex);
                            return;
                        }

                        // Kontostandanzeige aktualisieren:
                        KontostandTextField.setText(String.valueOf(konto.kontoStand()));

                        StatusLabel.setInfoText(DoneMessage);
                    }
                }
            } catch (NumberFormatException e1) {
                StatusLabel.setErrorText("Ungueltiger Betrag!");
            }
        } else if (e.getSource() == SerienEinzahlenButton) {
            try {

                // Einzuzahlender Betrag
                double betrag = Double.parseDouble(BetragsTextField.getText());

                //- Pruefung des Kontofeldinhalts
                String kontoID = KontoTextField.getText();
                if (kontoID == null || kontoID.equals("")) {
                    StatusLabel.setErrorText("Kontofeld leer bzw. null");
                } else {

                    KontoImplBase konto = (KontoImplBase) nameservice.lookup(kontoID);
                    if (konto == null) {
                        StatusLabel.setErrorText("Konto exisitiert nicht!");
                        return;
                    }

                    for (int i = 0; i < 1000; i++) {
                        StatusLabel.setInfoText("Serieneinzahlung laeuft...  noch" + (999 - i) + "offen");
                        try {
                            konto.einzahlen(betrag);
                        } catch (KontoException ex) {
                            StatusLabel.setErrorText("Einzahlen nicht moeglich: " + ex);
                            return;
                        }
                    }

                    // Kontostandanzeige aktualisieren:
                    KontostandTextField.setText(String.valueOf(konto.kontoStand()));

                    StatusLabel.setInfoText(DoneMessage);
                }
            } catch (NumberFormatException e1) {
                StatusLabel.setErrorText("Ungültiger Betrag!");
            }
        }
    }

    /**
     * @param args
     */
    public static void main(String[] args) {
        Geldautomat kundenDienst = new Geldautomat();
        kundenDienst.setVisible(true);
    }
}
